#include "datacenter.h"
#include <QStandardPaths>
#include <QJsonObject>
#include <QJsonDocument>
#include <QDir>

namespace model
{
    //静态成员在类外初始化
    DataCenter* DataCenter::instance = nullptr;

    model::DataCenter *model::DataCenter::getInstance()
    {
        if(instance == nullptr)
        {
            instance = new DataCenter();
        }
        return instance;
    }

    void DataCenter::initDataFile()
    {
        //拼装一个文件目录，appData作为目录
        QString basePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
        QString filePath = basePath + "/ChatClient.json";
        LOG() << filePath;


        //若目录不存在，创建目录
        QDir dir;
        if(!dir.exists(basePath))
        {
            dir.mkdir(basePath);
        }

        QFile file(filePath);
        if(!file.open(QIODevice::WriteOnly | QIODevice::Text))
        {
            LOG() << "初始化目录文件打开失败，error:" << file.errorString();
            return;
        }

        QString data = "{\n\n}";
        file.write(data.toUtf8());
        file.close();
    }

    void DataCenter::saveDataToFile()
    {
        QString filePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/ChatClient.json";
        QFile file(filePath);

        // LOG() << "持久化文件的位置：" << filePath;

        if(!file.open(QIODevice::WriteOnly | QIODevice::Text))
        {
            LOG() << "向文件中写时，打开文件失败,error:" << file.errorString();
            return;
        }

        QJsonObject jsonObj;
        jsonObj["loginSessionId"] = loginSessionId;

        QJsonObject jsonUnRead;
        for(auto it = unReadMessageCount->begin(); it != unReadMessageCount->end(); ++it)
        {
            jsonUnRead[it.key()] = it.value();
        }

        jsonObj["unRead"] = jsonUnRead;

        //写入文件中

        QJsonDocument jsonDoc(jsonObj);
        QString str = jsonDoc.toJson();
        file.write(str.toUtf8());
        file.close();
    }

    void DataCenter::loadDataFromFile()
    {
        LOG() << "加载持久化的数据";
        QString filePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/ChatClient.json";

        QFileInfo fileInfo(filePath);
        if(!fileInfo.exists())
        {
            //文件不存在，创建文件,写入{}内容
            initDataFile();
        }

        QFile file(filePath);

        if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
        {
            LOG() << "读文件时，打开文件失败,error:" << file.errorString();
            return;
        }

        QJsonDocument jsonDoc = QJsonDocument::fromJson(file.readAll());
        if(jsonDoc.isNull())
        {
            LOG() << "解析json文件失败！ json格式错误";
            file.close();
            return;
        }
        //解析loginSessionId
        QJsonObject jsonObj = jsonDoc.object();
        this->loginSessionId = jsonObj["loginSessionId"].toString();
        LOG() << "loginSessionId:" << this->loginSessionId;
        //解析unReadMessageCount
        this->unReadMessageCount->clear();
        QJsonObject jsonUnread = jsonObj["unRead"].toObject();
        for(auto it = jsonUnread.begin(); it != jsonUnread.end(); ++it)
        {
            this->unReadMessageCount->insert(it.key(),it.value().toInt());
        }
        file.close();
    }

    void DataCenter::initWebSocket()
    {
        netClient.initWebSocket();
    }

    ChatSessionInfo *DataCenter::findChatSessionById(const QString &chatSessionId)
    {
        if(chatSessionList == nullptr)
            return nullptr;
        for(auto& e : *chatSessionList)
        {
            if(e.sessionId == chatSessionId)
                return &e;
        }
        return nullptr;
    }

    ChatSessionInfo *DataCenter::findChatSessionByUserId(const QString &userId)
    {
        if(chatSessionList == nullptr)
            return nullptr;
        for(auto& e : *chatSessionList)
        {
            if(e.userId == userId)
                return &e;
        }
        return nullptr;
    }

    void DataCenter::topChatSessionInfo(const ChatSessionInfo &chatSessionInfo)
    {
        if(chatSessionList == nullptr)
            return;
        //1.找到这个元素
        auto it = chatSessionList->begin();
        for(; it != chatSessionList->end(); ++it)
        {
            if(it->sessionId == chatSessionInfo.sessionId)
            {
                break;
            }
        }

        if(it == chatSessionList->end())
            return;

        //2.把原列表中的元素备份，然后删除
        ChatSessionInfo backup = chatSessionInfo;
        chatSessionList->erase(it);
        //头插
        chatSessionList->push_front(backup);
    }

    void DataCenter::addMessage(const MessageInfo &message)
    {
        QList<MessageInfo>& messageList = (*recentMessage)[message.sessionId];
        messageList.push_back(message);
    }

    void DataCenter::clearUnread(const QString &chatSessionId)
    {
        (*unReadMessageCount)[chatSessionId] = 0;
        //持久化一下
        saveDataToFile();
    }

    void DataCenter::addUnread(const QString &chatSessionId)
    {
        ++(*unReadMessageCount)[chatSessionId];
        saveDataToFile();
    }

    int DataCenter::getUnread(const QString &chatSessionId)
    {
        return (*unReadMessageCount)[chatSessionId];
    }

    void DataCenter::getMyselfAsync()
    {
        netClient.getMyself(this->getLoginSessionId());
    }

    void DataCenter::resetMyself(std::shared_ptr<my::GetUserInfoRsp> pbResp)
    {
        if(myself == nullptr)
        {
            myself = new UserInfo();
        }
        const my::UserInfo& pbUserInfo = pbResp->userInfo();
        myself->load(pbUserInfo);
    }


    void DataCenter::getFriendListAsync()
    {
        netClient.getFriendList(this->getLoginSessionId());
    }

    void DataCenter::resetFriendList(std::shared_ptr<my::GetFriendListRsp> pbResp)
    {
        if(friendList == nullptr)
        {
            friendList = new QList<UserInfo>();
        }

        friendList->clear();

        QList<my::UserInfo>& pbFriendList = pbResp->friendList();
        for(auto& e : pbFriendList)
        {
            UserInfo userInfo;
            userInfo.load(e);
            friendList->push_back(userInfo);
        }

    }

    void DataCenter::getChatSessionListAsync()
    {
        netClient.getChatSessionList(loginSessionId);
    }

    void DataCenter::resetChatSessionLIst(std::shared_ptr<my::GetChatSessionListRsp> pbResp)
    {
        if(chatSessionList == nullptr)
        {
            chatSessionList = new QList<ChatSessionInfo>();
        }
        chatSessionList->clear();

        QList<my::ChatSessionInfo>& pbChatSessionInfo = pbResp->chatSessionInfoList();
        for(auto& e : pbChatSessionInfo)
        {
            ChatSessionInfo chatSessionInfo;
            chatSessionInfo.load(e);
            chatSessionList->push_back(chatSessionInfo);
        }

    }

    void DataCenter::getApplyListAsync()
    {
        netClient.getApplyList(loginSessionId);
    }

    void DataCenter::resetApplyList(std::shared_ptr<my::GetPendingFriendEventListRsp> pbResp)
    {
        if(applyList == nullptr)
        {
            applyList = new QList<UserInfo>();
        }
        applyList->clear();

        QList<my::FriendEvent>& pbApplyList = pbResp->event();
        for(auto& e : pbApplyList)
        {
            UserInfo userInfo;
            userInfo.load(e.sender());
            applyList->push_back(userInfo);
        }
    }

    void DataCenter::getRecentMessageAsync(const QString &chatSessionId,bool updateUi)
    {
        netClient.getRecentMessage(this->getLoginSessionId(),chatSessionId,updateUi);
    }

    void DataCenter::resetRecentMessageList(const QString& chatSessionId,std::shared_ptr<my::GetRecentMsgRsp> pbResp)
    {

        //这里必须是引用
        QList<MessageInfo>& messageList = (*recentMessage)[chatSessionId];
        // LOG() << "获取最近消息,共计:" << messageList.size();
        messageList.clear();
        int index = 1;
        for(auto& e : pbResp->msgList())
        {
            MessageInfo message;
            message.load(e);
            // LOG() << "第 " << index++ << "条消息，消息内容" <<  message.content;
            messageList.push_back(message);
        }
    }

    //返回指定会话ID最近的消息列表
    QList<MessageInfo> *DataCenter::getRecentMessageList(const QString &chatSessionId)
    {
        if(!recentMessage->contains(chatSessionId))
            return nullptr;
        return &(*recentMessage)[chatSessionId];
    }

    void DataCenter::sendTextMessageAsync(const QString &chatSessionId, const QString &content)
    {
        netClient.sendMessage(loginSessionId,chatSessionId,MessageType::TEXT_TYPE,content.toUtf8(),"");
    }

    void DataCenter::ChangeNickNameAsync(const QString &nickName)
    {
        netClient.changeNickName(loginSessionId,nickName);
    }

    void DataCenter::resetNickName(const QString &nickName)
    {
        myself->nickName = nickName;
    }

    void DataCenter::ChangeDescAscyc(const QString &desc)
    {
        netClient.changeDesc(loginSessionId,desc);
    }

    void DataCenter::resetDesc(const QString &desc)
    {
        if(myself == nullptr)
            return;
        myself->description = desc;
    }

    void DataCenter::getVerifycodeAsync(const QString &phone)
    {
        netClient.getVerifyCode(phone);
    }

    void DataCenter::resetVerifyCodeId(const QString &verifyCodeId)
    {
        LOG() << "保存验证码ID";
        currentVerifyId = verifyCodeId;
    }

    void DataCenter::changePhoneAsync(const QString &phone, const QString &verifyCodeId, const QString &verifyCode)
    {
        LOG() << "changePhoneAsync 调用";
        netClient.changePhone(loginSessionId,phone,verifyCodeId,verifyCode);
    }

    void DataCenter::resetPhone(const QString &phone)
    {
        if(myself == nullptr)
            return;
        // LOG() << "resetPhone 成功";
        myself->phoneNumber = phone;
    }

    void DataCenter::changeAvatarAsync(const QByteArray &imageBytes)
    {
        netClient.changeAvatar(loginSessionId,imageBytes);
    }

    void DataCenter::resetAvatar(const QByteArray& avatar)
    {
        if(myself == nullptr)
            return;
        myself->avatar = QByteArray2QIcon(avatar);
    }

    UserInfo *DataCenter::findFriendById(const QString &userId)
    {
        if(friendList == nullptr)
        {
            LOG() << "没有任何好友";
            return nullptr;
        }

        for(auto& e : *friendList)
        {
            if(e.userId == userId)
            {
                return &e;
            }
        }
        return nullptr;
    }

    void DataCenter::deleteFriendAsync(const QString &userId)
    {
        netClient.deleteFriend(loginSessionId,userId);
    }

    void DataCenter::removeFriend(const QString userId)
    {
        if(friendList == nullptr || chatSessionList == nullptr)
        {
            LOG() << "有指针为空";
            return;
        }

        //将好友列表删除
        friendList->removeIf([=](const UserInfo& userInfo){
            return userInfo.userId == userId;
        });

        //将对应的会话列表删除
        chatSessionList->removeIf([=](const ChatSessionInfo& chatSessionInfo){
            if(chatSessionInfo.userId == "")
            {
                //群聊，不受影响
                return false;
            }
            if(chatSessionInfo.userId == userId)
            {
                //判断当前打开的聊天界面，是否是要删除的
                if(chatSessionInfo.sessionId == this->currentSessionId)
                {
                    emit this->clearCurrentSession();
                }
                return true;
            }
            return false;
        });
    }

    void DataCenter::applyFriendAsync(const QString &userId)
    {
        netClient.applyFriend(loginSessionId,userId);
    }

    void DataCenter::agreeFriendApplyAsync(const QString &userId)
    {
        netClient.agreeFriendApply(loginSessionId,userId);
    }

    void DataCenter::rejectFriendApplyAsync(const QString &userId)
    {
        netClient.rejectFriendApply(loginSessionId,userId);
    }

    UserInfo DataCenter::removeFriendApply(const QString &userId)
    {
        if(applyList == nullptr)
        {
            LOG() << "好友申请列表为nullptr";
            return UserInfo();
        }

        for(auto it = applyList->begin(); it != applyList->end(); ++it)
        {
            if(it->userId == userId)
            {
                UserInfo user = *it;
                applyList->erase(it);
                return user;
            }
        }
        return UserInfo();
    }

    void DataCenter::createGroupChatSessionAsync(const QList<QString>& userIdList)
    {
        netClient.createGroupChatSession(loginSessionId,userIdList);
    }

    void DataCenter::getMemberListAsync(const QString &currentSessionId)
    {
        netClient.getMemberList(loginSessionId,currentSessionId);
    }

    void DataCenter::resetMemberList(const QString &chatSessionID, const QList<my::UserInfo> &memberList)
    {
        QList<UserInfo>& currentMemberList = (*this->memberList)[chatSessionID];
        currentMemberList.clear();

        for(auto& m : memberList)
        {
            UserInfo user;
            user.load(m);
            currentMemberList.push_back(user);
        }
    }

    QList<UserInfo>* DataCenter::getMemberList(const QString &chatSessionID)
    {
        if (!this->memberList->contains(chatSessionID)) {
            return nullptr;
        }
        return &(*this->memberList)[chatSessionID];
    }

    void DataCenter::searchUserAsync(const QString &searchKay)
    {
        netClient.searchUser(loginSessionId,searchKay);
    }

    void DataCenter::resetSearchUserResult(const QList<my::UserInfo> &userList)
    {
        if(searchFriendList == nullptr)
        {
            searchFriendList = new QList<UserInfo>();
        }
        searchFriendList->clear();
        for(const auto& u : userList)
        {
            UserInfo user;
            user.load(u);
            searchFriendList->push_back(user);
        }
    }

    QList<UserInfo> *DataCenter::getSearchUserResult()
    {
        return searchFriendList;
    }

    void DataCenter::getHistoryMessageByKeyAsync(const QString &searchKey)
    {
        netClient.getHistoryMessage(loginSessionId,this->getCurrentChatSessionId(),searchKey);
    }

    void DataCenter::getHistoryMessageByTimeAsync(const QDateTime &beginTime, const QDateTime &endTime)
    {
        netClient.getHistoryMessageByTime(loginSessionId,this->getCurrentChatSessionId(),beginTime,endTime);
    }

    void DataCenter::resetSearchHistoryMessageList(const QList<my::MessageInfo> &messageList)
    {
        if(this->searchMessageList == nullptr)
        {
            this->searchMessageList = new QList<MessageInfo>();
        }
        searchMessageList->clear();

        for(const auto& m : messageList)
        {
            MessageInfo messageInfo;
            messageInfo.load(m);
            this->searchMessageList->push_back(messageInfo);
        }
    }

    QList<MessageInfo> *DataCenter::getSearchMessageResult()
    {
        return searchMessageList;
    }

    void DataCenter::userLoginAsync(const QString &userName, const QString &password)
    {
        netClient.userLogin(userName,password);
    }

    void DataCenter::resetLoginId(const QString &loginSessionId)
    {
        this->loginSessionId = loginSessionId;
        //一旦会话改变，就需要进行持久化
        this->saveDataToFile();
    }

    void DataCenter::userRegisterAsync(const QString &userName, const QString &password)
    {
        netClient.userRegister(userName,password);
    }

    void DataCenter::phoneLoginAsync(const QString &phone, const QString &verifyCode)
    {
        netClient.phoneLogin(phone,currentVerifyId,verifyCode);
    }

    void DataCenter::phoneRegisterAsync(const QString &phone, const QString &verifyCode)
    {
        netClient.phoneRegister(phone,currentVerifyId,verifyCode);
    }

    void DataCenter::getSingleFileAsync(const QString &fileId)
    {
        netClient.getSingleFile(loginSessionId,fileId);
    }

    void DataCenter::sendImageMessageAsync(const QString &chatSessionId, const QByteArray &imageContent)
    {
        netClient.sendMessage(loginSessionId,chatSessionId,model::MessageType::IMAGE_TYPE,imageContent,"");
    }

    void DataCenter::sendFileMessageAsync(const QString &chatSessionId, const QString &fileName, const QByteArray &fileContent)
    {
        netClient.sendMessage(loginSessionId,chatSessionId,model::MessageType::FILE_TYPE,fileContent,fileName);
    }

    void DataCenter::sendSpeechMessageAsync(const QString &chatSessionId, const QByteArray &speechContent)
    {
        netClient.sendMessage(loginSessionId,chatSessionId,model::MessageType::SPEECH_TYPE,speechContent,"");
    }

    void DataCenter::speechConvertTextAsync(const QString &fileId, const QByteArray &speechContent)
    {
        netClient.speechConvertText(loginSessionId,fileId,speechContent);
    }

    DataCenter::DataCenter()
        :netClient(this)
    {
        //此处将几个hash类型的先实例化，为了使用hash中的key是否存在，判断值是否有效
        //其它几个QList类型的属性，暂时不实例化，使用nullptr表示非法状态

        memberList = new QHash<QString,QList<UserInfo>>();
        recentMessage = new QHash<QString,QList<MessageInfo>>();
        unReadMessageCount = new QHash<QString,int>();

        loadDataFromFile(); //加载持久化的数据
    }

    DataCenter::~DataCenter()
    {
        delete myself;
        delete friendList;
        delete chatSessionList;
        delete memberList;
        delete applyList;
        delete recentMessage;
        delete unReadMessageCount;
        delete searchMessageList;
        delete searchFriendList;
    }

}
